#pragma once

//多生产和多消费要维护两把锁——生产者 消费者之间的竞争 互相不影响——两把锁
#include <mutex>

#include <iostream>
#include <vector>
#include <semaphore.h>


static const int N=100;
template<class T>
class RingQueue
{
public:
    RingQueue(int num=N)
    :cap_(num),ring_(num)
    {
        sem_init(&_data_sem_,0,num);
        sem_init(&_space_sem_,0,0);
        c_step=p_step=0;
        pthread_mutex_init(&pmtx,nullptr); //第二个参数本质是一个union
        pthread_mutex_init(&cmtx,nullptr);

    }
    ~RingQueue()
    {
        sem_destroy(&_data_sem_);
        sem_destroy(&_space_sem_);
        pthread_mutex_destroy(&pmtx);
        pthread_mutex_destroy(&cmtx);

    }
    void P(sem_t& s)
    {
        sem_wait(&s);
    }
    void V(sem_t& s)
    {
        sem_post(&s);
    }
    void Lock(pthread_mutex_t & m)
    {
        pthread_mutex_lock(&m);
    }
    void Unlock(pthread_mutex_t & m)
    {
        pthread_mutex_unlock(&m);
    }
    void push(const T& in)
    {
          //首先检查——符合条件
        P(_space_sem_); //p
        //先加锁还是现申请信号量？？——信号量 先把对应的资源分给大家 然后持锁访问可以更快
        Lock(pmtx);
      
        //一定有对应的空间资源给我
        ring_[p_step++]=in;
        p_step%=cap_;
        Unlock(pmtx);
        V(_data_sem_);
      
    }
    void pop(T* out)
    {
        P(_data_sem_);
        Lock(cmtx);
        *out=ring_[c_step++];
        c_step%=cap_;
        Unlock(cmtx);
        V(_space_sem_);

    }
private:
    std::vector<T> ring_; //充当环形队列
    int cap_; //环形队列的大小
    //势必要使用信号量在不进入临界资源的前提下查看临界资源的多少
    sem_t _data_sem_; //消费者
    sem_t _space_sem_; //生产者
    int c_step; //消费位置
    int p_step; //生产位置
    pthread_mutex_t pmtx;
    pthread_mutex_t cmtx;
};